# -*- mode: Perl -*-
# /=====================================================================\ #
# |  pdfTeX                                                             | #
# | pdfTeX enhancements Implementation for LaTeXML                      | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;

# A rough initial draft of the extra commands & registers defined in pdfTeX.

# See the pdfTeX User's Manual

# Integer Registers
DefRegister('\pdfoutput'                => Number(0));
DefRegister('\pdfminorversion'          => Number(4));
DefRegister('\pdfoptionpdfminorversion' => Number(4));    # obsolete name
DefRegister('\pdfcompresslevel'         => Number(9));
DefRegister('\pdfobjcompresslevel'      => Number(0));
DefRegister('\pdfdecimaldigits'         => Number(4));
DefRegister('\pdfimageresolution'       => Number(72));
DefRegister('\pdfpkresolution'          => Number(0));
DefRegister('\pdftracingfonts'          => Number(0));
DefRegister('\pdfuniqueresname'         => Number(0));
DefRegister('\pdfadjustspacing'         => Number(0));
DefRegister('\pdfprotrudechars'         => Number(0));
# \efcode <font> <8bitnumber>  => <integer>
# \lpfcode <font> <8bitnumber> => <integer>
# \rpfcode <font> <8bitnumber> => <integer>
DefRegister('\efcode Token Number',   Number(0));
DefRegister('\lpcode Token Number',   Number(0));
DefRegister('\rpcode Token Number',   Number(0));
DefRegister('\knaccode Token Number', Number(0));
DefRegister('\knbccode Token Number', Number(0));
DefRegister('\knbscode Token Number', Number(0));
DefRegister('\shbscode Token Number', Number(0));
DefRegister('\stbscode Token Number', Number(0));
DefRegister('\tagcode Token Number',  Number(0));

DefRegister('\pdfforcepagebox'                => Number(0));
DefRegister('\pdfoptionalwaysusepdfpagebox'   => Number(0));
DefRegister('\pdfinclusionerrorlevel'         => Number(0));
DefRegister('\pdfoptionalinclusionerrorlevel' => Number(0));
DefRegister('\pdfimagehicolor'                => Number(0));
DefRegister('\pdfimageapplygamma'             => Number(0));
DefRegister('\pdfgamma'                       => Number(0));
DefRegister('\pdfimagegamma'                  => Number(0));
DefRegister('\pdfdraftmode'                   => Number(0));
DefRegister('\pdfadjustinterwordglue'         => Number(0));
DefRegister('\pdfappendkern'                  => Number(0));
DefRegister('\pdfgentounicode'                => Number(0));
DefRegister('\pdfinclusioncopyfonts'          => Number(0));
DefRegister('\pdfinfoomitdate'                => Number(0));
DefRegister('\pdfpagebox'                     => Number(0));
DefRegister('\pdfprependkern'                 => Number(0));
DefRegister('\pdfsuppressptexinfo'            => Number(0));
DefRegister('\pdfsuppresswarningdupdest'      => Number(0));
DefRegister('\pdfsuppresswarningdupmap'       => Number(0));
DefRegister('\pdfsuppresswarningpagegroup'    => Number(0));

# Dimen Registers
DefRegister('\pdfhorigin'         => Dimension('1in'));
DefRegister('\pdfvorigin'         => Dimension('1in'));
DefRegister('\pdfpagewidth'       => Dimension('0pt'));
DefRegister('\pdfpageheight'      => Dimension('0pt'));
DefRegister('\pdflinkmargin'      => Dimension('0pt'));
DefRegister('\pdfdestmargin'      => Dimension('0pt'));
DefRegister('\pdfthreadmargin'    => Dimension('0pt'));
DefRegister('\pdfpxdimen'         => Dimension('0pt'));
DefRegister('\pdfeachlinedepth'   => Dimension('0pt'));
DefRegister('\pdfeachlineheight'  => Dimension('0pt'));
DefRegister('\pdffirstlineheight' => Dimension('0pt'));
DefRegister('\pdfignoreddimen'    => Dimension('0pt'));
DefRegister('\pdflastlinedepth'   => Dimension('0pt'));

# Token Registers
DefRegister('\pdfpagesattr'     => Tokens());
DefRegister('\pdfpageattr'      => Tokens());
DefRegister('\pdfpageresources' => Tokens());
DefRegister('\pdfpkmode'        => Tokens());

# Expandable Commands
DefMacro('\pdftexrevision', '19');

DefMacro('\pdftexbanner',             '');
DefMacro('\pdfcreationdate',          '');
DefMacro('\pdfpageref Number',        '');
DefMacro('\pdfxformname Number',      '');
DefMacro('\pdffontname Token',        '');
DefMacro('\pdffontobjnum Token',      '');
DefMacro('\pdffontsize Token',        '');
DefMacro('\pdfincludechars Token {}', '');
DefMacro('\leftmarginkern Number',    '');
DefMacro('\rightmarginkern Number',   '');
DefMacro('\pdfescapestring {}',       '');
DefMacro('\pdfescapename {}',         '');
DefMacro('\pdfescapehex {}',          '');
DefMacro('\pdfunescapehex {}',        '');
# DefMacro('\ifpdfprimitive {}','');
# DefMacro('\ifpdfabsnum Number','');
# DefMacro('\ifpdfabsdim Dimension','');
DefMacro('\pdfuniformdeviate Number Token', '');
DefMacro('\pdfnormaldeviate Token',         '');
DefMacro('\pdfmdfivesum Number {}',         '');
DefMacro('\pdf@mdfivesum Number {}',        '');
DefMacro('\pdf@filemdfivesum Number {}',    '');
DefMacro('\pdffilesize{}', sub {
    # used in expl3's \__file_full_name:n , among others
    my ($gullet, $file) = @_;
    if (my $path = FindFile(ToString(Expand($file)))) {
      my @stat = stat $path;
      return (defined $stat[7]) ? Explode($stat[7]) : (); }
    else {
      return (); } });
DefMacro('\pdffilemoddate {}', '');
DefMacro('\pdffiledump {}',    '');
# DefMacro('\pdfcolorstackinit {}','');

# Read-only registers
DefRegister('\pdftexversion'           => Number(140));
DefRegister('\pdflastobj'              => Number(0));
DefRegister('\pdflastxform'            => Number(0));
DefRegister('\pdflastximage'           => Number(0));
DefRegister('\pdflastximagepages'      => Number(0));
DefRegister('\pdflastannot'            => Number(0));
DefRegister('\pdflastlink'             => Number(0));
DefRegister('\pdflastxpos'             => Number(0));
DefRegister('\pdflastypos'             => Number(0));
DefRegister('\pdflastdemerits'         => Number(0));
DefRegister('\pdfelapsedtime'          => Number(0));
DefRegister('\pdfrandomseed'           => Number(0));
DefRegister('\pdfshellescape'          => Number(0));
DefRegister('\pdflastximagecolordepth' => Number(0));
DefRegister('\pdfretval'               => Number(0));

# \pdfximage [ image attr spec ] general text (h, v, m)
# \pdfrefximage object number (h, v, m)
# \pdfannot annot type spec (h, v, m)
# Ugh, what a mess of ugly syntax....
DefParameterType('OpenActionSpecification', sub {
    my ($gullet) = @_;
    if (my $key = $gullet->readKeyword('openaction')) {
      if (my $action = $gullet->readKeyword('user', 'goto')) {
        # etc....
  } } },
  optional => 1, undigested => 1);

DefParameterType('OpenAnnotSpecification', sub {
    my ($gullet) = @_;
    my $general_text_param = LookupMapping('PARAMETER_TYPES', 'GeneralText');

    if    ($gullet->readKeyword('reserveobjnum')) { return; }
    elsif ($gullet->readKeyword('useobjnum')) {
      my $discard = $gullet->readNumber; }
    elsif ($gullet->readKeyword('stream')) {
      if ($gullet->readKeyword('attr')) {
        $gullet->skipSpaces;
        my $discard_stream = &{ $$general_text_param{reader} }($gullet); }
    }
    $gullet->skipSpaces;
    my $discard_spec = &{ $$general_text_param{reader} }($gullet);
    return; }
  , optional => 1, undigested => 1);

DefPrimitive('\pdfannot OpenAnnotSpecification', undef);

# \pdfstartlink [ rule spec ] [ attr spec ] action spec (h, m)
DefPrimitive('\pdfstartlink', undef);
# \pdfendlink (h, m)
DefPrimitive('\pdfendlink', undef);
# \pdfoutline outline spec (h, v, m)
# \pdfdest dest spec (h, v, m)
# \pdfthread thread spec (h, v, m)
# \pdfstartthread thread spec (v, m)
# \pdfendthread (v, m)
# \pdfsavepos (h, v, m)

# See lxRDFa for ideas how this info might be used!
DefMacro('\pdfinfo{}', '');

DefMacro('\pdfcatalog{} OpenActionSpecification', '');
DefMacro('\pdfnames{}',                           {});
DefMacro('\pdftrailer{}',                         {});
DefMacro('\pdfmapfile{}',                         '');
DefMacro('\pdfmapline{}',                         '');
# \pdffontattr font general text
# \pdffontexpand font expand spec
# \vadjust [ pre spec ] filler { vertical mode material } (h, m)
DefMacro('\quitvmode', '');
# \pdfliteral [ pdfliteral spec ] general text (h, v, m)
DefPrimitive('\pdfliteral OptionalMatch:direct OptionalMatch:page GeneralText', undef);
# \special pdfspecial spec
# \pdfresettimer
DefPrimitive('\pdfresettimer',           undef);
DefPrimitive('\pdfresettimerresettimer', undef);
# \pdfsetrandomseed number
# \pdfnoligatures font
# \pdfprimitive control sequence
# TODO: https://tex.stackexchange.com/questions/13771/let-a-control-sequence-to-a-redefined-primitive
DefMacro('\pdfprimitive DefToken', '#1');    # we can just ignore the advanced effects for now.
# \pdfcolorstack stack number stack action general text
DefPrimitive('\pdfcolorstack Number OptionalMatch:set OptionalMatch:push OptionalMatch:pop OptionalMatch:current', sub {
    # for now, carefully read and discard all arguments
    my ($stomach, $number, $set, $push, $pop, $current) = @_;
    return if ($pop);
    my $gullet = $stomach->getGullet;
    $gullet->skipSpaces;
    my $general_text_param = LookupMapping('PARAMETER_TYPES', 'GeneralText');
    my $discard            = &{ $$general_text_param{reader} }($gullet);
    return; });
DefPrimitive('\pdfobj OpenAnnotSpecification', sub {
    # for now, carefully read and discard all arguments
    return; });
# [ stream [ attr spec ] ] object contents
DefMacro('\pdfsetmatrix', '');
DefMacro('\pdfsave',      '');
DefMacro('\pdfrestore',   '');

# general text → { balanced text }
# attr spec → attr general text
# resources spec → resources general text
# rule spec → ( width | height | depth ) dimension [ rule spec ]
# object type spec → reserveobjnum |
# [ useobjnum number ]
# [ stream [ attr spec ] ] object contents
# annot type spec → reserveobjnum |
# [ useobjnum number ] [ rule spec ] general text
# object contents → file spec | general text
# xform attr spec → [ attr spec ] [ resources spec ]
# image attr spec → [ rule spec ] [ attr spec ] [ page spec ] [ colorspace spec ] [ pdf box spec ]
# outline spec → [ attr spec ] action spec [ count number ] general text
# action spec → user user-action spec | goto goto-action spec |
# thread thread-action spec
# user-action spec → general text
# goto-action spec → numid |
# [ file spec ] nameid |
# [ file spec ] [ page spec ] general text |
# file spec nameid newwindow spec |
# file spec [ page spec ] general text newwindow spec
# thread-action spec → [ file spec ] numid | [ file spec ] nameid
# open-action spec → openaction action spec
# colorspace spec → colorspace number
# pdf box spec → mediabox | cropbox | bleedbox | trimbox | artbox
# map spec → { [ map modifier ] balanced text }
# map modifier → + | = | -
# numid → num number
# nameid → name general text
# newwindow spec → newwindow | nonewwindow
# dest spec → numid dest type | nameid dest type
# dest type → xyz [ zoom number ] | fitr rule spec |
# fitbh | fitbv | fitb | fith | fitv | fit
# thread spec → [ rule spec ] [ attr spec ] id spec
# id spec → numid | nameid
# file spec → file general text
# page spec → page number
# expand spec → stretch shrink step [ autoexpand ]
# stretch → number
# shrink → number
# step → number
# pre spec → pre
# pdfliteral spec → direct | page
# pdfspecial spec → { [ pdfspecial id [ pdfspecial modifier ] ] balanced text }
# pdfspecial id → pdf: | PDF:
# pdfspecial modifier → direct:
# stack action → set | push | pop | current

DefMacro('\expanded Expanded', '#1');

DefMacro('\pdfstrcmp Expanded Expanded', sub {
    my $cmp = (ToString($_[1]) cmp ToString($_[2]));
    return ($cmp == 1 ? T_OTHER('1')
      : ($cmp == 0 ? T_OTHER('0')
        : Tokens(T_OTHER('-'), T_OTHER('1')))); });
1;
